﻿#pragma once
#include "Kind.hpp"
#include "Text/TextSpan.hpp"

#include <iostream>
#include <memory>
#include <sstream>
#include <string>
#include <vector>

class SyntaxNode;
// 定义类型;
typedef std::shared_ptr<SyntaxNode> SharedNode;

class SyntaxNode
{
private:
    SyntaxKind Kind;
    std::string NodeName;

public:
    SyntaxNode(SyntaxKind kind, std::string name) : Kind(kind), NodeName(name) {}
    SyntaxKind GetKind() { return this->Kind; }

    virtual std::vector<SharedNode> GetChildren() { return {}; };

    std::string GetNodeName() const { return this->NodeName; }
    virtual std::string GetName() const { return ""; }

    virtual TextSpan GetSpan() const
    {
        size_t start = 0, end = 0;
        // auto childrens = this->GetChildren();
        // auto size = childrens.size();
        // if (childrens.size() != 0)
        // {
        //     end = childrens.back()->
        // }
        return TextSpan::FromBounds(start, end);
    }

    // 输出 PrettyPrint Tree;
    void WriteTo(std::ostream &os) { PrettyPrint(os, this); }

    // 输出 PrettyPrint Tree;
    std::string ToString()
    {
        std::stringstream os;
        this->WriteTo(os);
        return os.str();
    }
    //~SyntaxNode()
private:
    void static PrettyPrint(std::ostream &os, SyntaxNode *node, std::string indent = "", bool isLast = true)
    {
        std::string marker = isLast ? "└──" : "├──";

        os << indent << marker << SyntaxKindName::GetTokenName(node->GetKind());

        switch (node->GetKind())
        {
        case SyntaxKind::Number:
        case SyntaxKind::True:
        case SyntaxKind::False:
        {
            os << " " << node->GetName();
            break;
        }
        default:
            break;
        }

        os << std::endl;

        indent += isLast ? "   " : "│  ";

        const size_t childrenSize = node->GetChildren().size();

        for (int i = 0; i < childrenSize; i++)
        {
            PrettyPrint(os, node->GetChildren()[i].get(), indent, i == (childrenSize - 1));
        }
    }
};
